﻿// ParseLib - An open source library for natural language processing.
// Copyright (C) Kais Dukes, 2012. E-mail: kais@kaisdukes.com
// http://parselib.org

using System;
using System.Collections.Generic;
using System.Linq;
using ParseLib.Corpora;

namespace ParseLib.Tagging.Brill
{
    public class LexiconBuilder
    {
        public Lexicon BuildLexicon(IEnumerable<TextualUnit> trainingData)
        {
            // Read all tokens in the training data.
            var map = new Dictionary<string, TagFrequency[]>();
            TagFrequency[] allTags = null;
            foreach (var token in trainingData.SelectMany(x => x))
            {
                // All tags.
                AddTag(token.PartOfSpeech, ref allTags);

                // Token.
                TagFrequency[] tags;
                map.TryGetValue(token.Text, out tags);
                if (AddTag(token.PartOfSpeech, ref tags))
                {
                    map[token.Text] = tags;
                }
            }

            // Build the lexicon.
            var lexicon = new Lexicon { DefaultTagList = GetTagList(allTags) };
            foreach (var pair in map)
            {
                lexicon.Add(pair.Key, GetTagList(pair.Value));
            }
            return lexicon;
        }

        private static PartOfSpeech[] GetTagList(IList<TagFrequency> frequencies)
        {
            var size = frequencies.Count;
            var tags = new PartOfSpeech[size];
            for (var i = 0; i < size; i++)
            {
                tags[i] = frequencies[i].Tag;
            }
            return tags;
        }

        private static bool AddTag(PartOfSpeech tag, ref TagFrequency[] tags)
        {
            // New word?
            if (tags == null)
            {
                tags = new[] {new TagFrequency {Tag = tag, Count = 1}};
                return true;
            }

            // Existing tag?
            var size = tags.Length;
            for (var i = 0; i < size; i++)
            {
                if (tags[i].Tag != tag) continue;
                tags[i].Count++;
                return false;
            }

            // New tag.
            var newTags = new TagFrequency[size + 1];
            Array.Copy(tags, newTags, size);
            newTags[size] = new TagFrequency {Tag = tag, Count = 1};
            Array.Sort(newTags, (a, b) => b.Count.CompareTo(a.Count)); // Descending.
            tags = newTags;
            return true;
        }
    }
}